#include "RegistroArbol.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

RegistroArbol::RegistroArbol() {
	clave = NULL;
	dato = NULL;
}

RegistroArbol::RegistroArbol(Clave* clave, Dato* dato, char tipo) {
	Clave * aux;
	if (clave->getTipo() == 'i') {
		aux = new ClaveInt(clave->toChar());
	} else
		aux = new ClaveChar(clave->toChar(), clave->getTamanio());
	if ((tipo == 'N') || (tipo == 'R')) {
		DatoNodoInterno *auxDato = new DatoNodoInterno(dato->toChar(),
				dato->getTamanio());
		this->dato = auxDato;
	} else {
		DatoChar *auxDato = new DatoChar(dato->toChar(), dato->getTamanio());
		this->dato = auxDato;
	}
	this->clave = aux;
	this->tipo = tipo;
}

RegistroArbol::RegistroArbol(const RegistroArbol& registroArbol) {
	Clave * aux;
	this->tipo = const_cast<RegistroArbol&> (registroArbol).getTipo();
	if (const_cast<RegistroArbol&> (registroArbol).getClave()->getTipo() == 'i') {
		aux
				= new ClaveInt(
						const_cast<RegistroArbol&> (registroArbol).getClave()->toChar());
	} else
		aux
				= new ClaveChar(
						const_cast<RegistroArbol&> (registroArbol).getClave()->toChar(),
						const_cast<RegistroArbol&> (registroArbol).getClave()->getTamanio());
	if ((tipo == 'N') || (tipo == 'R')) {
		DatoNodoInterno
				*auxDato =
						new DatoNodoInterno(
								const_cast<RegistroArbol&> (registroArbol).getDato()->toChar(),
								const_cast<RegistroArbol&> (registroArbol).getDato()->getTamanio());
		this->dato = auxDato;
	} else {
		DatoChar
				*auxDato =
						new DatoChar(
								const_cast<RegistroArbol&> (registroArbol).getDato()->toChar(),
								const_cast<RegistroArbol&> (registroArbol).getDato()->getTamanio());
		this->dato = auxDato;
	}
	this->clave = aux;
}

RegistroArbol& RegistroArbol::operator=(const RegistroArbol& registroArbol) {
	if (clave)
		delete clave;
	if (dato)
		delete dato;
	Clave * aux;
	this->tipo = const_cast<RegistroArbol&> (registroArbol).getTipo();
	if (const_cast<RegistroArbol&> (registroArbol).getClave()->getTipo() == 'i') {
		aux = new ClaveInt(const_cast<RegistroArbol&> (registroArbol).getClave()->toChar());
	} else
		aux = new ClaveChar(const_cast<RegistroArbol&> (registroArbol).getClave()->toChar(),
							const_cast<RegistroArbol&> (registroArbol).getClave()->getTamanio());
	if ((tipo == 'N') || (tipo == 'R')) {
		DatoNodoInterno* auxDato = new DatoNodoInterno(
										const_cast<RegistroArbol&> (registroArbol).getDato()->toChar(),
										const_cast<RegistroArbol&> (registroArbol).getDato()->getTamanio());
		this->dato = auxDato;
	} else {
		DatoChar* auxDato = new DatoChar(
								const_cast<RegistroArbol&> (registroArbol).getDato()->toChar(),
								const_cast<RegistroArbol&> (registroArbol).getDato()->getTamanio());
		this->dato = auxDato;
	}
	this->clave = aux;
	return (*this);
}

/*Crea un registro a partir de una cadena valida de caracteres*/
RegistroArbol* RegistroArbol::crearRegistro(stringstream* fuente, char tipo) {
	/*Creamos un nuevo Registro con la informacion traducida*/
	char cAuxTDato[TAM_TDATO];
	char cAuxTClave[TAM_TCLAVE];
	char tClave[1];
	int tamanioDato, tamanioClave;
	fuente->seekg(0);
	/*Leemos los 1eros 5bytes, que representan el tamanio clave y el tipo*/
	fuente->read(tClave, 1);

	//cout << "REGARBOL " << tClave[0] << endl;

	fuente->read(cAuxTClave, TAM_TCLAVE);
	tamanioClave = Util::charToInt(cAuxTClave);
	fuente->read(cAuxTDato, TAM_TDATO);
	tamanioDato = Util::charToInt(cAuxTDato);

	/*Leemos la clave*/
	char* auxClave = new char[tamanioClave]; 
	fuente->read(auxClave, tamanioClave);

	/*Leemos el dato*/
	char* auxDato = new char[tamanioDato];
	fuente->read(auxDato, tamanioDato);

	if ((tipo == 'N') || (tipo == 'R')) {
		RegistroArbol * auxreg;
		DatoNodoInterno *auxDat = new DatoNodoInterno(auxDato, tamanioDato);
		if (tClave[0] == 'i') {
			ClaveInt* auxCla = new ClaveInt(auxClave);
			auxreg = new RegistroArbol(auxCla, auxDat, tipo);
			delete auxCla;
		} else {
			ClaveChar* auxCla = new ClaveChar(auxClave, tamanioClave);
			auxreg = new RegistroArbol(auxCla, auxDat, tipo);
			delete auxCla;
		}
		delete auxDat;
		return auxreg;
		/*Creamos un nuevo Registro con la informacion traducida*/
	} else {
		RegistroArbol * auxreg;
		DatoChar *auxDat = new DatoChar(auxDato, tamanioDato);
		if (tClave[0] == 'i') {
			ClaveInt* auxCla = new ClaveInt(auxClave);
			auxreg = new RegistroArbol(auxCla, auxDat, tipo);
			delete auxCla;
		} else {
			ClaveChar* auxCla = new ClaveChar(auxClave, tamanioClave);
			auxreg = new RegistroArbol(auxCla, auxDat, tipo);
			delete auxCla;
		}
		delete auxDat;
		return auxreg;
		//return new RegistroArbol(new Clave(auxClave,tamanioClave),new DatoPPMC(auxDato), tipo);
	}
	if (auxClave != NULL) delete auxClave;
	if (auxDato != NULL) delete auxDato;
}

char RegistroArbol::getTipo() {
	return tipo;
}

/*Convierte un registro a su equivalente en cadena */
stringstream* RegistroArbol::toStream() {
	char* cDato = this->dato->toChar();
	char* cClave = this->clave->toChar();
	char tClave[1];
	tClave[0] = this->clave->getTipo();
	unsigned int tamClave = this->clave->getTamanio();
	char* cTamanioClave = Util::intToChar(tamClave, TAM_TCLAVE);
	stringstream* result = new stringstream();
	result->seekp(0);

	unsigned int tamDato = this->dato->getTamanio();
	char* cTamanioDato = Util::intToChar(tamDato, TAM_TDATO);

	result->write(tClave, 1);
	result->write(cTamanioClave, TAM_TCLAVE);
	result->write(cTamanioDato, TAM_TDATO);
	result->write(cClave, tamClave);
	result->write(cDato, tamDato);

	delete cTamanioClave;
	delete cTamanioDato;

	return result;
}

unsigned int RegistroArbol::getTamanio() {
	return (getClave()->getTamanio() + getDato()->getTamanio() + TAM_META_REG);
}

Dato* RegistroArbol::getDato() {
	return dato;
}

Clave* RegistroArbol::getClave() {
	return clave;
}
void RegistroArbol::setDato(Dato& nuevoDato) {
	if (dato){
		delete dato;
		dato = NULL;
	}
	char* auxChar =nuevoDato.toChar();
	this->dato = new DatoChar(auxChar, nuevoDato.getTamanio());
	delete auxChar;
}

void RegistroArbol::setClave(Clave& nuevaClave) {
	if (clave){
		delete clave;
		clave = NULL;
	}
	char* auxChar = nuevaClave.toChar();
	if (nuevaClave.getTipo() == 'i') {
		clave = new ClaveInt(auxChar);
	} else
		clave = new ClaveChar(auxChar, nuevaClave.getTamanio());
	//delete auxChar;
}

RegistroArbol::~RegistroArbol() {
	if (clave) delete (clave);
	if (dato) delete (dato);
	//	clave=NULL;
	//	dato=NULL;
}
